﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using RGoodSW.Logger.Interfaces;
using RGoodSW.Logger.MvcHelper.Models;
using CodeCamp.Infrastructure;
using CCM = CodeCamp.Model;
using CodeCamp.Models.Presenters;
using CodeCamp.Models.Shared;
using SWS = System.Web.Security;
#if USE_WIF
using MIC = Microsoft.IdentityModel.Claims;
using SSP = System.Security.Principal;
#endif

namespace CodeCamp.Controllers
{
  public class PresentersController : ControllerBase
  {
    public PresentersController(IDefaultValueProvider defaultValueProvider, ILoggerExtended logger)
      : base(defaultValueProvider, logger)
    {
    }

    #region List actions

    // GET: /Presenters/List

    public ActionResult List( string eventName )
    {
      using (var repository = new CodeCampDataRepository())
      {
          var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
          var siteUser = GetSiteUser(repository, this.User, true);
          SetSharedViewBagProperties(ccEvent);

          bool showCancelledSessions = (this.User.IsInRole(CCRoles.RoleNames.BigCheeze) || this.User.IsInRole(CCRoles.RoleNames.EventContentEditor)
                                || this.User.IsInRole(CCRoles.RoleNames.EventTrackLead));

          var eventPresenters =
            repository.GetPresenters(ccEvent.Id)
            .Where(p => p.SessionPresenters.Count > 0)
            .OrderBy(p => p.LastName)
            .ThenBy(p => p.FirstName);

          var userPresenterId = GetPresenterId(ccEvent.Id, siteUser);

          var presenters = new List<PresentersListViewModel.Presenter>();
          foreach (var presenter in eventPresenters)
          {
              int nonPublicCount = 0;
              var sessions = new List<PresentersListViewModel.Presenter.Session>();
              foreach (var sessionPresenter in presenter.SessionPresenters)
              {
                  var session = sessionPresenter.Session;
                  bool sessionIsPublic = SessionIsPublic(session);
                  if (!sessionIsPublic)
                      nonPublicCount++;

                  if (sessionIsPublic || showCancelledSessions)
                  {
                      var presenterSession = new PresentersListViewModel.Presenter.Session
                      {
                          SessionId = session.Id,
                          Title = SessionTitle(session)
                      };
                      sessions.Add(presenterSession);
                  }
              }

              if (sessions.Count > 0)
              {
                  presenters.Add(
                    new PresentersListViewModel.Presenter
                    {
                        PresenterId = presenter.Id,
                        Name = string.Format("{0} {1}", presenter.FirstName, presenter.LastName),
                        TwitterName = presenter.TwitterName,
                        BlogUrl = CorrectedUrl(presenter.BlogUrl),
                        WebsiteUrl = CorrectedUrl(presenter.WebsiteUrl),
                        Biography = presenter.Biography,
                        Sessions = sessions
                    });
              }
          }

          var model = new PresentersListViewModel
          {
              Presenters = presenters,
              ShowCancelledSessions = showCancelledSessions,

              //IsUserAuthenticated = User.Identity.IsAuthenticated,
              //IsUserAPresenter = userPresenterId != null,
              UserPresenterId = userPresenterId != null
                ? userPresenterId.Value
                : 0
          };
          SetSharedEventProperties(ccEvent, model, repository);

          return View("List", model);
      }
    }

    private string CorrectedUrl(string rawUrl)
    {
        string correctedUrl = rawUrl;
        if (!string.IsNullOrEmpty(rawUrl))
        {
            if ((rawUrl.ToLower().IndexOf("http://") != 0)
                && (rawUrl.ToLower().IndexOf("https://") != 0))
            {
                correctedUrl = string.Concat("http://", rawUrl);
            }
        }
        return correctedUrl;
    }

    #endregion

    #region Details actions

    private PresentersDetailsViewModel FillPresenterDetailModel(CCM.Presenter presenter, bool includeAdvancedDataIfBigCheeze,
        Nullable<TimeSpan> localTimeConversion, IEnumerable<PresentersDetailsViewModel.Session> sessions, string speakerRateSpeakerUrl)
    {
        PresentersDetailsViewModel model = null;
        if (this.User.IsInRole(CCRoles.RoleNames.BigCheeze) && includeAdvancedDataIfBigCheeze)
        {
            PresentersDetailsViewModelAdvanced advancedmodel = new PresentersDetailsViewModelAdvanced
            {
                EventId = presenter.EventId,
                PresenterSiteUserId = presenter.SiteUserId
            };
            if (presenter.SiteUser != null)
            {
                CCM.SiteUser siteUser = presenter.SiteUser;
                advancedmodel.PresenterSiteUserId = siteUser.Id;
                advancedmodel.SiteUserEmailAddress = siteUser.EmailAddress;
                advancedmodel.UserClaimEmailAddress = siteUser.UserClaimEmailAddress;
                advancedmodel.UserIdentityClaim = siteUser.UserIdentityClaim;
                advancedmodel.UserIdentityClaimType = siteUser.UserIdentityClaimType;
                advancedmodel.UserIdentityIssuer = siteUser.UserIdentityIssuer;
                advancedmodel.UserIdentityProvider = siteUser.UserIdentityProvider;
            }
            model = advancedmodel;
        }
        else
        {
            model = new PresentersDetailsViewModel()
            {
                PresenterSiteUserId = presenter.SiteUserId
            };
        }
        if (this.User.IsInRole(CCRoles.RoleNames.BigCheeze) || this.User.IsInRole(CCRoles.RoleNames.EventTrackLead))
        {
            model.PrivateInfo = new PresenterDetailPrivateInformation();
            model.PrivateInfo.PresenterEmailAddress = presenter.EmailAddress;
            model.PrivateInfo.PresenterMobilePhone = presenter.MobilePhone;
            model.PrivateInfo.OrganizerNotes = presenter.OrganizerNotes;
            model.PrivateInfo.PrivateNotes = presenter.PrivateNotes;
            if (presenter.SiteUserId.HasValue && presenter.SiteUser.LastOnlineActivityUTC.HasValue)
            {
                if (localTimeConversion.HasValue)
                {
                    model.PrivateInfo.LastActivity = presenter.SiteUser.LastOnlineActivityUTC.Value.AddMinutes(localTimeConversion.Value.TotalMinutes);
                }
                else
                {
                    model.PrivateInfo.LastActivity = presenter.SiteUser.LastOnlineActivityUTC;
                    model.PrivateInfo.LastActivitySuffix = "(UTC)";
                }
            }
        }
#if USE_MEMBERSHIP
          model.MembershipEnabled = true;
#endif
        model.CurrentUserAuthorizedToEdit = IsCurrentUserAuthorizedToEdit(presenter);
        model.PresenterId = presenter.Id;
        model.Name = string.Format("{0} {1}", presenter.FirstName, presenter.LastName);
        model.TwitterName = presenter.TwitterName;
        model.Biography = presenter.Biography;
        model.Sessions = sessions.ToList();
        bool presenterIsAuthorizedToEdit = IsPresenterAuthorizedToEdit(presenter);
        if (presenterIsAuthorizedToEdit)
        {
            if (!User.IsInRole(CCRoles.RoleNames.Presenter))
                model.UserIsNewPresenter = true;
            else
                model.PresenterIsAuthorizedToEdit = true;
        }
        model.BlogUrl = CorrectedUrl(presenter.BlogUrl);
        model.WebsiteUrl = CorrectedUrl(presenter.WebsiteUrl);
        model.SpeakerRateSpeakerUrl = speakerRateSpeakerUrl;
        return model;
    }

    // GET: /Presenters/Details/5

    public ActionResult Details( int id, string eventName )
    {
      SetLoggerThreadContextData();
      using (var repository = new CodeCampDataRepository())
      {
          var event_ = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
          SetSharedViewBagProperties(event_);
          int eventId = event_.Id;
          var presenter = repository.GetPresenter(event_.Id, id);

          if (presenter == null)
          {
              Logger.WarnFormat("Presenter {0} for event {1} not found.", id, event_.Id);
              //return new HttpNotFoundResult("Presenter not found");
              return RedirectToAction("List");
          }
          var sessions =
            from sessionPresenters in presenter.SessionPresenters
            orderby sessionPresenters.Session.Title
            select new PresentersDetailsViewModel.Session
            {
                SessionId = sessionPresenters.Session.Id,
                Title = sessionPresenters.Session.Title
            };

          var speakerRateSpeaker = repository.GetSpeakerRateSpeaker(presenter.Id);
          var speakerRateSpeakerUrl = speakerRateSpeaker != null ? speakerRateSpeaker.SpeakerUrl : null;

          PresentersDetailsViewModel model = FillPresenterDetailModel(presenter, false, null, sessions, speakerRateSpeakerUrl);
          if (User.IsInRole(CCRoles.RoleNames.BigCheeze) || User.IsInRole(CCRoles.RoleNames.EventTrackLead))
          {
              model.InsiderFormInfo = new PresenterDetailsInsiderFormInfo()
              {
                  PresenterId = presenter.Id
              };
          }

          SetSharedEventProperties(event_, model, repository);

          return View("Details", model);
      }
    }

    private List<CCM.EmailItem> GetPresenterEmailList(CodeCampDataRepository ccdr, CCM.Presenter presenter, bool includeEmailToSiteUser)
    {
        List<CCM.EmailItem> emailList = presenter.EmailItems.ToList();
        if (includeEmailToSiteUser && presenter.SiteUserId.HasValue)
        {
            var siteUserEmails = ccdr.EFContext.EmailItems
                                .Where(ei => ei.SiteUserId.HasValue
                                    && (ei.SiteUserId.Value == presenter.SiteUserId.Value)
                                    && !ei.PresenterId.HasValue)
                                .ToList();
            foreach (var item in siteUserEmails)
            {
                emailList.Add(item);
            }
        }
        return emailList;
    }

    const string PresenterInsiderRoles = CCRoles.RoleNames.EventTrackLead + ", " + CCRoles.RoleNames.BigCheeze;
    [CustomAuthorize(Roles = PresenterInsiderRoles, Message = "You are not authorized to edit the presenter profile.")]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Details(string eventName, PresenterDetailsInsiderFormInfo model)
    {
      SetLoggerThreadContextData();
      using (var ccdr = new CodeCampDataRepository())
      {
          var event_ = EventsHelper.GetEvent(ccdr, eventName, DefaultEventShortName, this.User);
          SetSharedViewBagProperties(event_);
          int eventId = event_.Id;
          var presenter = ccdr.GetPresenter(event_.Id, model.PresenterId);

          if (presenter == null)
          {
              Logger.WarnFormat("Presenter {0} for event {1} not found.", model.PresenterId, event_.Id);
              //return new HttpNotFoundResult("Presenter not found");
              return RedirectToAction("List");
          }

          var sessions =
            from sessionPresenters in presenter.SessionPresenters
            orderby sessionPresenters.Session.Title
            select new PresentersDetailsViewModel.Session
            {
                SessionId = sessionPresenters.Session.Id,
                Title = sessionPresenters.Session.Title
            };

          var speakerRateSpeaker = ccdr.GetSpeakerRateSpeaker(presenter.Id);
          var speakerRateSpeakerUrl = speakerRateSpeaker != null ? speakerRateSpeaker.SpeakerUrl : null;

          bool includeAdvancedDataIfBigCheeze = false;
          bool showEmailsToPresenter = false;
          bool includeEmailsToSiteUser = false;
          Nullable<TimeSpan> localTimeConversion = null; // LocalTimeConversion;
          if (ModelState.IsValid)
          {
              includeAdvancedDataIfBigCheeze = model.ShowAdvancedPresenterDetails;
              includeEmailsToSiteUser = model.IncludeEmailToSiteUser;
              showEmailsToPresenter = model.ShowEmailSentToPresenter;
              if (model.UTCAdjustMinutes.HasValue)
                  localTimeConversion = new TimeSpan(0, model.UTCAdjustMinutes.Value, 0);
          }
          PresentersDetailsViewModel viewModel = FillPresenterDetailModel(presenter, includeAdvancedDataIfBigCheeze,
              localTimeConversion, sessions, speakerRateSpeakerUrl);
          viewModel.InsiderFormInfo = model;
          if (showEmailsToPresenter)
          {
              viewModel.EmailList = EmailController.GetEmailItemsList(GetPresenterEmailList(ccdr, presenter, includeEmailsToSiteUser));
          }
          SetSharedEventProperties(event_, viewModel, ccdr);
          return View("Details", viewModel);
      }
    }

    #endregion

    private bool IsPresenterAuthorizedToEdit(CCM.Presenter presenter)
    {
        if ((presenter != null) && (presenter.SiteUser != null))
        {
            return (presenter.SiteUser.IsApproved && !presenter.SiteUser.IsLockedOut);
        }
        return false;
    }

    private bool ThisUserIsSiteUserForPresenter(CCM.Presenter presenter)
    {
        if ((presenter != null) && (presenter.SiteUser != null))
        {
            return UserMatchesSiteUser(this.User, presenter.SiteUser);
        }
        return false;
    }

    private bool IsThisUserPresenterAndAuthorizedToEdit(CCM.Presenter presenter)
    {
        if (!IsPresenterAuthorizedToEdit(presenter))
            return false;
        if (ThisUserIsSiteUserForPresenter(presenter)
            && User.IsInRole(CCRoles.RoleNames.Presenter))
            return true;
        return false;
    }

    private bool IsCurrentUserAuthorizedToEdit(CCM.Presenter presenter)
    {
        if (presenter == null)
            return false;
        if (User.IsInRole(CCRoles.RoleNames.EventContentEditor))
            return true;
        if (User.IsInRole(CCRoles.RoleNames.BigCheeze))
            return true;

        return IsThisUserPresenterAndAuthorizedToEdit(presenter);
    }

    #region Add actions

    // GET: /Presenters/Add

    [CustomAuthorize]
    public ActionResult Add( string eventName )
    {
      //int eventId = EventsHelper.GetEventId( eventName );
        using (var repository = new CodeCampDataRepository())
        {
            var event_ = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
            SetSharedViewBagProperties(event_);
            CCM.SiteUser siteUser = GetSiteUser(repository, this.User, true);
            if (siteUser == null)
                return RedirectToAction("RegisterUser", "Account", new { eventName = eventName });

            CCM.Presenter presenter = SiteUserPresenter(siteUser, event_.Id);
            if (presenter != null)
            {
                return RedirectToAction("Edit", new { id = presenter.Id });
            }

            string identityEmailAddress = null;

            //Check if there is a "disconnected" presenter (i.e. presenter added to database but no identity provider set)
            identityEmailAddress = siteUser.EmailAddress;
            if (!string.IsNullOrWhiteSpace(identityEmailAddress))
            {
                presenter = repository.GetDisconnectedPresenter(event_.Id, identityEmailAddress);
                if (presenter != null)
                {
                    bool presenterUpdated = false;
                    try
                    {
                        if (!presenter.SiteUserId.HasValue)
                        {
                            presenter.SiteUserId = siteUser.Id;
                            repository.Save();
                            presenterUpdated = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorFormat(new LogContextData(this.User, this.Request), ex,
                            "{1} connecting presenter to user \"{0}\": {2}", this.User.Identity.Name, ex.GetType(), ex.Message);
                        string foo = ex.Message;
                    }
                    if (presenterUpdated)
                        return RedirectToAction("Edit", new { id = presenter.Id } );
                }
            }
            PresentersEditViewModel model = new PresentersEditViewModel
            {
                HideNotes = true
            };

            if (!string.IsNullOrWhiteSpace(identityEmailAddress))
            {
                model.EmailAddress = identityEmailAddress;

                if (event_.PriorEventProfileReuseAllowed)
                {
                    var oldProfile = repository.GetPriorPresenterProfile(event_.Id, identityEmailAddress);
                    if (oldProfile != null)
                    {
                        model = new PresentersEditViewModel
                        {
                            FirstName = oldProfile.FirstName,
                            LastName = oldProfile.LastName,
                            EmailAddress = identityEmailAddress,
                            BlogUrl = oldProfile.BlogUrl,
                            ShirtSize = oldProfile.ShirtSize,
                            TwitterName = oldProfile.TwitterName,
                            WebsiteUrl = oldProfile.WebsiteUrl,
                            HideNotes = true
                        };
                        if (!string.IsNullOrWhiteSpace(oldProfile.Biography))
                            model.Biography = oldProfile.Biography;
                    }
                }
            }
            if (model == null)
                model = new PresentersEditViewModel { EmailAddress = identityEmailAddress };

            model.FirstName = siteUser.FirstName;
            model.LastName = siteUser.LastName;

            SetSharedEventProperties(event_, model, repository);

            return View("Add", model);
        }
    }

    // POST: /Presenters/Add

    [AcceptVerbs( HttpVerbs.Post )]
    [CustomAuthorize]
    public ActionResult Add(PresentersEditViewModel model, string eventName)
    {
      try
      {
          using (var repository = new CodeCampDataRepository())
          {
              var event_ = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
              SetSharedViewBagProperties(event_);
              CCM.SiteUser siteUser = GetSiteUser(repository, this.User, true);
              if (siteUser == null)
                  return RedirectToAction("RegisterUser", "Account", new { eventName = eventName });

              int eventId = event_.Id;
              if (ModelState.IsValid)
              {
                  var presenter = new CCM.Presenter
                  {
                      //UserIdentityName = User.Identity.Name,
                      EventId = eventId,
                      FirstName = model.FirstName,
                      LastName = model.LastName,
                      EmailAddress = model.EmailAddress,
                      MobilePhone = model.MobilePhone,
                      TwitterName = model.TwitterName,
                      BlogUrl = model.BlogUrl,
                      WebsiteUrl = model.WebsiteUrl,
                      ShirtSize = model.ShirtSize,
                      SiteUser = siteUser,
                      SiteUserId = siteUser.Id
                  };
                  if (!string.IsNullOrWhiteSpace(model.Biography))
                  {
                      CCM.PresenterBiography bio = new CCM.PresenterBiography()
                      {
                          Content = model.Biography,
                          Presenter = presenter
                      };
                      //presenter.PresenterBiography = bio;
                      presenter.PresenterBiographies.Add(bio);
                  }
                  repository.AddSiteUserToRole(siteUser, LogName(siteUser), CCRoles.RoleNames.Presenter, true);
                  repository.Add(presenter);
                  repository.Save();

                  //if (!Roles.IsUserInRole(CCRoles.RoleNames.Presenter))
                  //    Roles.AddUserToRole(User.Identity.Name, CCRoles.RoleNames.Presenter);

                  if (!string.IsNullOrEmpty(model.SpeakerRateSpeakerUrl))
                  {
                      var speakerRateSpeaker = new CCM.SpeakerRateSpeaker
                        {
                            PresenterId = presenter.Id,
                            SpeakerUrl = model.SpeakerRateSpeakerUrl
                        };
                      repository.Add(speakerRateSpeaker);
                      repository.Save();
                  }
                  RemoveLocalClaims(this.User);
                  return RedirectToAction("Details", new { id = presenter.Id });
              }
              model.FirstName = siteUser.FirstName;
              model.LastName = siteUser.LastName;
              model.HideNotes = true;

              SetSharedEventProperties(event_, model, repository);

              return View("Add", model);
          }
      }
      catch (Exception ex)
      {
          Logger.ErrorFormat(new LogContextData(this.User, this.Request), ex,
              "{1} adding presenter for user \"{0}\": {2}", this.User.Identity.Name, ex.GetType(), ex.Message);
          string etype = ex.GetType().ToString();
          ModelState.AddModelError("", "Error saving profile");
          return View("Add", model);
      }
    }

    #endregion

    #region Edit actions

    // GET: /Presenters/Edit/5

    const string PresenterEditRoles = CCRoles.RoleNames.Presenter + ", " + CCRoles.RoleNames.EventContentEditor + ", " + CCRoles.RoleNames.BigCheeze;
    [CustomAuthorize(Roles = PresenterEditRoles, Message = "You are not authorized to edit the presenter profile.")]
    public ActionResult Edit(Nullable<int> id, string eventName)
    {
      using (var repository = new CodeCampDataRepository())
      {
          SetLoggerThreadContextData();
          Logger.DebugFormat("Edit(id={0}, eventName=\"{1}\")",
              id,
              eventName
              );
          try
          {
              var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
              if (ccEvent.ShortName != eventName)
                  return RedirectToAction("List");

              var siteUser = GetSiteUser(repository, this.User, true);
              if (siteUser == null)
                  return RedirectToAction("List");

              SetSharedViewBagProperties(ccEvent);
              int eventId = ccEvent.Id;

              CCM.Presenter presenter = null;
              if (id.HasValue)
                  presenter = repository.GetPresenter(eventId, id.Value);
              else
                  presenter = GetPresenter(eventId, siteUser);

              if (presenter == null)
                  return RedirectToAction("List");

              // verify that user is authorized to edit this presenter profile
              if (!IsCurrentUserAuthorizedToEdit(presenter))
              {
                  LogPresenterNotAuthorized("Edit", presenter, id);
                  ErrorViewModel evm = new ErrorViewModel();
                  SetSharedEventProperties(ccEvent, evm, repository);
                  return View("PresenterEditAuthorizationError", evm);
              }

              //TODO: Check this when adding claims auth
              if ((siteUser.Id == presenter.SiteUserId) && !repository.SiteUserIsInRole(siteUser.Id, CCRoles.RoleNames.Presenter))
              {
                  repository.AddSiteUserToRole(siteUser, this.User.Identity.Name, CCRoles.RoleNames.Presenter, true);
                  repository.Save();
              }

              var speakerRateSpeaker = repository.GetSpeakerRateSpeaker(presenter.Id);

              var model = new PresentersEditViewModel
              {
                  PresenterId = presenter.Id,
                  FirstName = presenter.FirstName,
                  LastName = presenter.LastName,
                  TwitterName = presenter.TwitterName,
                  EmailAddress = presenter.EmailAddress,
                  MobilePhone = presenter.MobilePhone,
                  Biography = presenter.Biography,
                  BlogUrl = presenter.BlogUrl,
                  WebsiteUrl = presenter.WebsiteUrl,
                  ShirtSize = presenter.ShirtSize,
                  SpeakerRateSpeakerUrl = speakerRateSpeaker == null ? null : speakerRateSpeaker.SpeakerUrl,
                  PrivateNotes = presenter.PrivateNotes,
                  HideNotes = false
              };

              if (User.IsInRole(CCRoles.RoleNames.BigCheeze) || User.IsInRole(CCRoles.RoleNames.EventContentEditor))
                  model.OrganizerNotes = presenter.OrganizerNotes;

              SetSharedEventProperties(ccEvent, model, repository);

              return View("Edit", model);
          }
          catch (Exception ex)
          {
              Logger.ErrorFormat(new LogContextData(this.User, this.Request), ex,
                  "{1} getting presenter for user \"{0}\": {2}", this.User.Identity.Name, ex.GetType(), ex.Message);
              return View("Error2");
          }
      }
    }

    private void LogPresenterNotAuthorized(string action, CCM.Presenter presenter, int id)
    {
        Nullable<int> id_ = id;
        LogPresenterNotAuthorized(action, presenter, id_);
    }

    private void LogPresenterNotAuthorized(string action, CCM.Presenter presenter, Nullable<int> id)
    {
        Logger.WarnFormat(new LogContextData(this.User, this.Request),
            "User not authorized for \"{1}\" on id {2}. {0}id of presenter found={3}, presenter.SiteUserId={4}.  ",
            Environment.NewLine,
            action,
            id,
            presenter == null ? -1 : presenter.Id,
            presenter == null ? -1 : presenter.SiteUserId
            );
    }

    // POST: /Presenters/Edit/5
    [AcceptVerbs(HttpVerbs.Post)]
    [CustomAuthorize(Roles = PresenterEditRoles)]
    public ActionResult Edit(PresentersEditViewModel model, string eventName, Nullable<int> id)
    {
        try
        {
            SetLoggerThreadContextData(); 
            Logger.DebugFormat("Edit({0}.Id={1}, \"{2}\", {3})",
                (model == null) ? "?" : model.GetType().Name,
                (model == null) ? -1 : model.PresenterId,
                eventName,
                id
                );
            using (var repository = new CodeCampDataRepository())
            {
                var ccEvent = EventsHelper.GetEvent(repository, eventName, DefaultEventShortName, this.User);
                SetSharedViewBagProperties(ccEvent);
                int eventId = ccEvent.Id;
                CCM.Presenter presenter = null;
                if (!id.HasValue && model.PresenterId != 0)
                    id = model.PresenterId;

                if (id.HasValue)
                    presenter = repository.GetPresenter(eventId, id.Value);

                // verify that user is authorized to edit this presenter profile
                if (!IsCurrentUserAuthorizedToEdit(presenter))
                {
                    LogPresenterNotAuthorized("Edit-Post", presenter, id);
                    ErrorViewModel evm = new ErrorViewModel();
                    SetSharedEventProperties(ccEvent, evm, repository);
                    return View("PresenterEditAuthorizationError", evm);
                }

                if (ModelState.IsValid)
                {
                    CCM.SiteUser siteUser = GetSiteUser(repository, this.User);

                    //presenter.UserIdentityName = User.Identity.Name;
                    presenter.FirstName = model.FirstName;
                    presenter.LastName = model.LastName;
                    presenter.TwitterName = model.TwitterName;
                    presenter.EmailAddress = model.EmailAddress;
                    presenter.MobilePhone = model.MobilePhone;
                    presenter.BlogUrl = model.BlogUrl;
                    presenter.WebsiteUrl = model.WebsiteUrl;
                    presenter.ShirtSize = model.ShirtSize;
                    presenter.UpdatedUTC = DateTime.UtcNow;
                    presenter.UpdatedBy = UpdateUser(siteUser);
                    if (!model.HideNotes)
                    {
                        presenter.PrivateNotes = model.PrivateNotes;
                        if (User.IsInRole(CCRoles.RoleNames.BigCheeze) || User.IsInRole(CCRoles.RoleNames.EventContentEditor))
                            presenter.OrganizerNotes = model.OrganizerNotes;
                    }

                    //Where Presenter and SiteUser duplicate properties,
                    //Update SiteUser as needed 
                    bool siteUserUpdated = false;
                    if (model.FirstName != presenter.SiteUser.FirstName)
                    {
                        presenter.SiteUser.FirstName = model.FirstName;
                        siteUserUpdated = true;
                    }
                    if (model.LastName != presenter.SiteUser.LastName)
                    {
                        presenter.SiteUser.LastName = model.LastName;
                        siteUserUpdated = true;
                    }
                    if (model.EmailAddress != presenter.SiteUser.EmailAddress)
                    {
                        presenter.SiteUser.EmailAddress = model.EmailAddress;
                        siteUserUpdated = true;
                    }
                    if (siteUserUpdated)
                    {
                        presenter.SiteUser.UpdatedUTC = DateTime.UtcNow;
                        if (siteUser != null) //Should always return a result, but to be safe... 
                            presenter.SiteUser.UpdatedBy = UpdateUser(siteUser);
                    }

                    //Commented out 7/3/2012 - can cause problems now that 3rd party can edit
                    //TODO: Would this EVER change? - revisit when doing claims auth
                    //if (string.IsNullOrWhiteSpace(presenter.UserIdentityClaim))
                    //{
                    //    presenter.UserIdentityClaim = User.Identity.Name;
                    //    presenter.SetUniqueUserIdentifier();
                    //}

                    //if (presenter.PresenterBiographyId.HasValue)
                    if (presenter.PresenterBiographies.Count > 0)
                    {
                        if (!string.IsNullOrWhiteSpace(model.Biography))
                        {
                            presenter.PresenterBiographies[0].Content = model.Biography;
                        }
                        else
                        {
                            CCM.PresenterBiography oldBio = presenter.PresenterBiographies[0];
                            oldBio.Presenter = null;
                            presenter.PresenterBiographies.Remove(oldBio);
                            repository.EFContext.PresenterBiographies.Remove(oldBio);
                        }
                    }
                    else
                    {
                        if (!string.IsNullOrWhiteSpace(model.Biography))
                        {
                            CCM.PresenterBiography newBio = new CCM.PresenterBiography()
                            {
                                Content = model.Biography,
                                Presenter = presenter
                            };
                            //presenter.PresenterBiography = newBio;
                            presenter.PresenterBiographies.Add(newBio);
                        }
                    }

                    var speakerRateSpeaker = repository.GetSpeakerRateSpeaker(presenter.Id);
                    if (speakerRateSpeaker != null)
                    {
                        if (string.IsNullOrEmpty(model.SpeakerRateSpeakerUrl))
                            repository.Delete(speakerRateSpeaker);
                        else
                            speakerRateSpeaker.SpeakerUrl = model.SpeakerRateSpeakerUrl;
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(model.SpeakerRateSpeakerUrl))
                            repository.Add(new CCM.SpeakerRateSpeaker
                              {
                                  PresenterId = presenter.Id,
                                  SpeakerUrl = model.SpeakerRateSpeakerUrl
                              });
                    }
                    repository.Save();

                    return RedirectToAction("Details", new { id = presenter.Id });
                }
                model.HideNotes = false;
                return View("Edit", model);
            }
        }
        catch (System.Data.Entity.Infrastructure.DbUpdateException ex)
        {
            Logger.ErrorFormat(new LogContextData(this.User, this.Request), ex,
                "{1} saving presenter edit for user \"{0}\": {2}", this.User.Identity.Name, ex.GetType(), ex.Message);
            ModelState.AddModelError("", "Error saving presenter edits.");
            return View("Edit", model);
        }
        catch (Exception ex)
        {
            Logger.ErrorFormat(new LogContextData(this.User, this.Request), ex,
                "{1} saving presenter edit for user \"{0}\": {2}", this.User.Identity.Name, ex.GetType(), ex.Message);
            ModelState.AddModelError("", "Error saving presenter edits.");
            return View("Edit", model);
        }
    }

    #endregion

    #region Tests

    [CustomAuthorize]
    public ActionResult Test2(string eventName)
    {
        System.Text.StringBuilder testMsg = new System.Text.StringBuilder();
        return Test(eventName, "Presenters/Test2", testMsg);
    }

    [CustomAuthorize(Roles = PresenterEditRoles)]
    public ActionResult Test3(string eventName)
    {
        System.Text.StringBuilder testMsg = new System.Text.StringBuilder();
        return Test(eventName, "Presenters/Test3", testMsg);
    }

    [CustomAuthorize(Roles = PresenterEditRoles)]
    public ActionResult Test4(Nullable<int> id, string eventName)
    {
        using (var ccdr = new CodeCampDataRepository())
        {
            System.Text.StringBuilder testMsg = new System.Text.StringBuilder();
            var ccEvent = EventsHelper.GetEvent(ccdr, eventName, DefaultEventShortName, this.User);
            testMsg.AppendFormat("Test4 Event.Id={1}, id={2}{0}",
                Environment.NewLine,
                ccEvent.Id,
                id);

            var siteUser = GetSiteUser(ccdr, this.User, true);
            if (siteUser != null)
                testMsg.AppendFormat("SiteUser.Id={1} name={2} {3}{0}", Environment.NewLine, siteUser.Id, siteUser.FirstName, siteUser.LastName);
            CCM.Presenter presenter = null;
            if (id.HasValue)
                presenter = ccdr.GetPresenter(ccEvent.Id, id.Value);
            else
                presenter = GetPresenter(ccEvent.Id, siteUser);
            if (presenter != null)
            {
                testMsg.AppendFormat("presenter.Id={1} name=\"{2} {3}\"{0}IsCurrentUserAuthorizedToEdit={4}{0}",
                    Environment.NewLine,
                    presenter.Id,
                    presenter.FirstName,
                    presenter.LastName,
                    IsCurrentUserAuthorizedToEdit(presenter));
            }

            return Test(eventName, "Presenters/Test4", ccdr, ccEvent, testMsg);
        }
    }

    #endregion
  }
}
